<?php
/**
 * Konfiguracja modułów
 *  
 * @author gabriel
 */
class Admin_Model_Modules extends Promotor_Model_Abstract {

	/**
	 * @param string|array|Zend_Config $options
	 * @return void
	 */
	protected function __construct($options = null) {
		if ($options instanceof Zend_Config) {
			$options = $options->toArray();
		} else
		if (is_string($options)) {
			$options = array(
				'modulesPath' => $options
			);
		} else
		if (!is_array($options)) {
			$options = array();
		}
		
		$this->setOptions($options);

		$this->getModulesPath();
	}

	/**
	 * @var Admin_Model_Modules
	 */
	protected static $_instance;
	
	/**
	 * @param null|string|array|Zend_Config $options
	 * @return Admin_Model_Modules
	 */
	public static function getInstance($options = null) {
		if (null === self::$_instance) {
			self::$_instance = new self($options);
		}
		return self::$_instance;
	} 

	/**
	 * @param array $options
	 * @return void
	 */
	public function setOptions(array $options) {
		foreach ($options as $name => $value) {
			$method = 'set' . ucfirst($name);
			if (method_exists($this, $method)) {
				$this->$method($value);
			}
		}
	}

	/**
	 * @var string
	 */
	protected $_modulesPath;

	/**
	 * @param string $path
	 * @return Admin_Model_Modules
	 * @throws Exception
	 */
	public function setModulesPath($path) {
		if (is_dir($path)) {
			$this->_modulesPath = (string) $path;
			return $this;
		}
		throw new Exception(sprintf('modules path do not exsists'));
	}

	/**
	 * @return string
	 */
	public function getModulesPath() {
		if (null === $this->_modulesPath) {
			if (defined('APP_MODULES_PATHNAME')) {
				$this->setModulesPath(APP_MODULES_PATHNAME);
			}
		}
		return $this->_modulesPath;
	}

	const LIST_ALL = 'LIST_ALL';
	const LIST_MODULES_NAMES = 'LIST_MODULES_NAMES';
	
	/**
	 * @var array
	 */
	protected $_list;

	/**
	 * Return enabled modules paths names!
	 * 
	 * @param string $flag
	 * @return array
	 */
	public function getList($flag = self::LIST_ALL) {
		if (null === $this->_list) {
			$this->_list = Zend_Controller_Front::getInstance()->getControllerDirectory();
			// strip last dirname (it should be a 'controller' dir name)
			$this->_list = array_map('dirname', $this->_list);
		}

		switch($flag) {
			default:
			case self::LIST_ALL:
				return $this->_list;

			case self::LIST_MODULES_NAMES:
				return array_keys($this->_list);
		}
	}

	/**
	 * @var array
	 */
	protected $_modules;
	
	/**
	 * Return all modules (enabled & disabaled )
	 * 
	 * @param string $flag
	 * @return array
	 */
	public function getAllList($flag = null) {
		if (null === $this->_modules)
		{
			$this->_modules = array();
			$pathname = $this->getModulesPath();
			$iterator = new DirectoryIterator($pathname);

			while ($iterator->valid())
			{
				if ($iterator->isDir() && !$iterator->isDot())
				{
					$filename = $iterator->getFilename();
					// nazwa modułu tylko alfa..
					if (preg_match('/^[\w]+$/', $filename)) {
						$this->_modules[$filename] = $iterator->getPathname();
					}
				}
				$iterator->next();
			}
		}
		
		switch($flag) {
			default:
			case self::LIST_ALL:
				return $this->_modules;

			case self::LIST_MODULES_NAMES:
				return array_keys($this->_modules);
		}
	}
	
	/**
	 * Zwraca listę włączonych modułów.. ale w konfiguracji!
	 * 
	 * @return array
	 */
	public function getEnabledList() {
		$result = array();

		$modules = $this->getAllList();
		foreach ($modules as $name => $pathfile) {
			if ($this->isEnabled($name)) {
				$result[$name] = $pathfile;
			}
		}
		
		return $result;
	}
	
	/**
	 * @var unknown_type
	 */
	protected $_configFilename = 'module.xml';
	
	/**
	 * @param string $path
	 * @return string
	 */
	public function getConfigFilename($path = null) {
		return null === $path 
			? $this->_configFilename
			: rtrim($path, '/') . '/' . $this->_configFilename;
	}

	/**
	 * @var array
	 */
	protected $_config = array();
	
	/**
	 * @param string $module
	 * @return Zend_Config
	 */
	public function getConfig($module) {
		if (!isset($this->_config[$module])) {
			$modules = $this->getAllList();
			if (!isset($modules[$module])) {
				throw new Promotor_Model_Exception(sprintf('module "%s" do not exsists', $module));
			}
			
			$filename = $this->getConfigFilename($modules[$module]);
			if (!is_file($filename)) {
				throw new Promotor_Model_Exception(sprintf('module "%s" configuration do not exsists', $module));
			}

			$this->_config[$module] = new Zend_Config_Xml($filename, null, true);
		}
		return $this->_config[$module];
	}

	/**
	 * @param string $module
	 * @return bool
	 */
	public function hasConfig($module) {
		$modules = $this->getAllList();
		if (isset($modules[$module])) {
			$filename = $this->getConfigFilename($modules[$module]);
			if (is_file($filename)) {
				return true;
			}
		}
		return false;
 	}

	/*public function saveConfig() {
		
	}*/

	/**
	 * @param $module
	 * @return bool
	 */
	public function isEnabled($module) {
		if (!$this->hasConfig($module)) {
			return false;
		}

		$enabled = $this->getConfig($module)->enabled;

		if (is_numeric($enabled)) {
			$enabled = (bool) $enabled;
		} else
		if (is_string($enabled))
		{
			switch (strtolower($enabled))
			{
				case 'true':
				case 'yes':
					$enabled = true;
					break;

				default:
				case 'false':
				case 'no':
					$enabled = false;
					break;
			}
		} else {
			$enabled = false;
		}

		return $enabled;
	}

	/**
	 * @param string $module
	 */
	public function setDisable($module) {
		$module = (string) $module;

		try {
			$config = $this->getConfig($module);
			$this->_setStatus(self::SUCCESS);
		} catch (Promotor_Model_Exception $e) {
			$this->_addException($e);
			$this->_setStatus(self::FAILURE);

			return;
		}
		
		$config->enabled = 'false';
		
		/**
		 * nie sprawdzam czy "$modules[$module]" istnieje bo
		 * 'hasConfig()' już to sprawdza 
		 */
		$modules = $this->getAllList();
		$filename = $this->getConfigFilename($modules[$module]);

		try { 
			$xml = new Zend_Config_Writer_Xml();
			$xml->setFilename($filename);
			$xml->setConfig($config);
			$xml->write();

			$this->_setStatus(self::SUCCESS);
		} catch (Zend_Config_Exception $e) {
			$this->_addException($e);

			$this->_setStatus(self::FAILURE);
		}
	}
	
	/**
	 * @param string $module
	 */
	public function setEnable($module) {
		$module = (string) $module;

		try {
			$config = $this->getConfig($module);
			$this->_setStatus(self::SUCCESS);
		} catch (Promotor_Model_Exception $e) {
			$this->_addException($e);
			$this->_setStatus(self::FAILURE);

			return;
		}
		
		$config->enabled = 'true';

		/**
		 * nie sprawdzam czy "$modules[$module]" istnieje bo
		 * 'hasConfig()' już to sprawdza 
		 */
		$modules = $this->getAllList();
		$filename = $this->getConfigFilename($modules[$module]);

		try { 
			$xml = new Zend_Config_Writer_Xml();
			$xml->setFilename($filename);
			$xml->setConfig($config);
			$xml->write();

			$this->_setStatus(self::SUCCESS);
		} catch (Zend_Config_Exception $e) {
			$this->_addException($e);

			$this->_setStatus(self::FAILURE);
		}
	}
	
	/**
	 * @var Zend_Navigation
	 */
	protected $_navigation;

	/**
	 * @return Zend_Navigation
	 */
	public function getNavigation() {
		if (null === $this->_navigation) {
			$this->_navigation = new Zend_Navigation();

			foreach ($this->getList(self::LIST_MODULES_NAMES) as $module) {
				if ($this->isEnabled($module)) {
					$config = $this->getConfig($module);
					if (isset($config->options)
							&& isset($config->options->navigation)
							&& $config->options->navigation instanceof Zend_Config)
					{
						// add navigation
						$this->_navigation->addPages($config->options->navigation);
					} else
					if (isset($config->options)
							&& isset($config->options->navigation_include)
							&& $config->options->navigation_include instanceof Zend_Config)
					{
//						$page = Zend_Navigation_Page::factory($config->options->navigation_include);
//						$page->removePages();
//						
//						if ($this->_navigation->hasPage($page)) {
//							var_dump(true);
////							$this->_navigation->
//						} else {
//							var_dump(false);
//						}
						
						// add navigation
						$this->_navigation->addPages($config->options->navigation_include);
					}
					
				}
			}
		}
		return $this->_navigation;
	}
}